<template>
  <div id="map"></div>
</template>

<script setup>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import {
  CSS2DObject,
  CSS2DRenderer,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";
import * as d3 from "d3";
import { onMounted, ref } from "vue";
import ChinaData from "@/json/china.json";
import shaanxi from "@/json/shaanxi.json";

/**
 * 初始化设置
 */
// 初始化场景
const scene = new THREE.Scene();

// 初始化相机
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  1,
  2000
);
camera.position.set(0, 64, 64);
// camera.lookAt(0, 0, 0);

// // 添加坐标轴
// const axesHelper = new THREE.AxesHelper(5);
// scene.add(axesHelper);

// 初始化渲染器
const labelRenderer = new CSS2DRenderer();
labelRenderer.domElement.style.position = "absolute";
labelRenderer.domElement.style.top = "0px";
labelRenderer.domElement.style.pointerEvents = "none";
labelRenderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(labelRenderer.domElement);

const renderer = new THREE.WebGLRenderer({
  antialias: true, // 抗锯齿
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比率，防止 Canvas 画布输出模糊
renderer.outputEncoding = THREE.sRGBEncoding;
document.body.appendChild(renderer.domElement);

// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement);

const render = () => {
  requestAnimationFrame(render);
  labelRenderer.render(scene, camera);
  renderer.render(scene, camera);
  controls && controls.update();
};

render();

// onresize 事件会在窗口被调整大小时发生
window.onresize = () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
};

/**
 * 光源设置
 */
// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);
scene.add(directionalLight);

// 环境光
const ambient = new THREE.AmbientLight(0xffffff, 0.5);
ambient.position.set(5, 10, 5);
scene.add(ambient);

// 矫正坐标
const offsetXY = d3.geoMercator();

const getRandomColor = () => {
  return "#" + Math.floor(Math.random() * 16777215).toString(16);
};

const setCenter = (map) => {
  map.rotation.x = -Math.PI / 2;
  const box = new THREE.Box3().setFromObject(map);
  const center = box.getCenter(new THREE.Vector3());
  map.position.x = map.position.x - center.x;
  map.position.z = map.position.z - center.z;
};

/**
 * 绘制每个市的区域
 * @param data 坐标数据
 * @param color 颜色
 * @param depth 深度
 * */
const createMesh = (data, color, depth) => {
  const shape = new THREE.Shape();
  data.forEach((item, idx) => {
    const [x, y] = offsetXY(item);

    if (idx === 0) shape.moveTo(x, -y);
    else shape.lineTo(x, -y);
  });

  const extrudeSettings = {
    depth,
    bevelEnabled: false,
  };
  const materialSettings = {
    color: color,
    emissive: 0x000000,
    roughness: 0.45,
    metalness: 0.8,
    transparent: true,
    side: THREE.DoubleSide,
  };
  const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
  const material = new THREE.MeshStandardMaterial(materialSettings);

  return new THREE.Mesh(geometry, material);
};

const createLine = (data, depth) => {
  const points = [];
  data.forEach((item) => {
    const [x, y] = offsetXY(item);
    points.push(new THREE.Vector3(x, -y, 0));
  });
  const lineGeometry = new THREE.BufferGeometry().setFromPoints(points);
  // 地图上面的线
  const upLineMaterial = new THREE.LineBasicMaterial({ color: "#000000" });
  // 地图下面的线
  const downLineMaterial = new THREE.LineBasicMaterial({ color: "#000000" });

  const upLine = new THREE.Line(lineGeometry, upLineMaterial);
  const downLine = new THREE.Line(lineGeometry, downLineMaterial);
  downLine.position.z = -0.1;
  upLine.position.z = depth + 0.1;
  return [upLine, downLine];
};

const createLabel = (name, point, depth) => {
  const div = document.createElement("div");
  div.id = "label";
  div.style.color = "#ffffff";
  div.style.fontSize = "12px";
  div.textContent = name;

  const label = new CSS2DObject(div);
  label.scale.set(0.01, 0.01, 0.01);
  const [x, y] = offsetXY(point);
  label.position.set(x, -y, depth);
  return label;
};

// 根据省市的json数据创建地图
const createMap = (data) => {
  const map = new THREE.Object3D();
  const center = data.features[0].properties.centroid;
  // d3的方法表示将center作为xy坐标系的0,0点
  offsetXY.center(center).translate([0, 0]);

  data.features.forEach((feature) => {
    const unit = new THREE.Object3D();
    const { centroid, center, name, adcode } = feature.properties;
    const { coordinates, type } = feature.geometry;

    const depth = 1;

    const label = createLabel(name, centroid || center || [0, 0], depth);

    coordinates.forEach((coordinate) => {
      if (type === "MultiPolygon") coordinate.forEach((item) => fn(item));
      if (type === "Polygon") fn(coordinate);

      function fn(coordinate) {
        unit.name = name;
        unit.adcode = adcode;
        const mesh = createMesh(coordinate, "#63bbd0", depth);
        unit.add(mesh);
        // 绘制每个市的边界
        const line = createLine(coordinate, depth);
        unit.add(mesh, ...line);
      }
    });
    map.add(unit, label);
    // 在地图上添加指定位置的圆形点
    // const latitude = 34.113794; // 示例经度
    // const longitude = 109.171795; // 示例纬度
    // '西安新氧环保科技有限公司'
  });
  console.log("map", map);

  setCenter(map);
  scene.add(map);

  window.addEventListener("click", (event) => {
    const mouse = new THREE.Vector2();
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    const raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster
      .intersectObjects(map.children)
      .filter((item) => item.object.type !== "Line");
    if (intersects.length > 0) {
      // 点击市
      if (intersects[0].object.type === "Mesh") {
        if (intersects[0].object.parent.name === "陕西省") {
          // renderer.render(scene, camera);
          // 清除场景中的所有对象
          // 获取所有 id 为 "label" 的 div 元素
          const labelDivs = document.querySelectorAll("div#label");

          // 遍历并移除每个元素
          labelDivs.forEach((div) => {
            div.remove();
          });
          scene.remove(map);
          // scene.children.forEach((child) => {
          //   scene.remove(child);
          //   // 如果是物体，释放资源
          //   if (child instanceof THREE.Mesh) {
          //     child.geometry.dispose();
          //     if (child.material) {
          //       if (Array.isArray(child.material)) {
          //         child.material.forEach((mat) => mat.dispose());
          //       } else {
          //         child.material.dispose();
          //       }
          //     }
          //   }
          // });
          createMap(shaanxi);
          console.log("点击市", intersects[0]);
        }
      }
    }
  });
};
createMap(ChinaData);
</script>

<style scoped></style>
